{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "20549885",
   "metadata": {},
   "source": [
    "# 使用 Milvus 和 DeepSeek 构建 RAG\n",
    "\n",
    "DeepSeek 帮助开发者使用高性能语言模型构建和扩展 AI 应用。它提供高效的推理、灵活的 API 以及先进的专家混合 (MoE) 架构，用于强大的推理和检索任务。\n",
    "\n",
    "在本教程中，我们将展示如何使用 Milvus 和 DeepSeek 构建一个检索增强生成 (RAG) 管道。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7394c701",
   "metadata": {},
   "source": [
    "## 准备工作"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "89103a1e",
   "metadata": {},
   "source": [
    "### 依赖与环境"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "9c18d7b4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Looking in indexes: https://mirrors.aliyun.com/pypi/simple/\n",
      "Collecting pymilvus==2.5.10 (from pymilvus[model]==2.5.10)\n",
      "  Downloading https://mirrors.aliyun.com/pypi/packages/b0/4b/847704930ad8ddd0d0975e9a3a5e3fe704f642debe97454135c2b9ee7081/pymilvus-2.5.10-py3-none-any.whl (227 kB)\n",
      "Collecting openai==1.82.0\n",
      "  Downloading https://mirrors.aliyun.com/pypi/packages/51/4b/a59464ee5f77822a81ee069b4021163a0174940a92685efc3cf8b4c443a3/openai-1.82.0-py3-none-any.whl (720 kB)\n",
      "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m720.4/720.4 kB\u001b[0m \u001b[31m1.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0ma \u001b[36m0:00:01\u001b[0m\n",
      "\u001b[?25hCollecting requests==2.32.3\n",
      "  Downloading https://mirrors.aliyun.com/pypi/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl (64 kB)\n",
      "Requirement already satisfied: tqdm==4.67.1 in /Users/taoxiaoyin/miniconda3/lib/python3.13/site-packages (4.67.1)\n",
      "Collecting torch==2.7.0\n",
      "  Downloading https://mirrors.aliyun.com/pypi/packages/90/48/7e6477cf40d48cc0a61fa0d41ee9582b9a316b12772fcac17bc1a40178e7/torch-2.7.0-cp313-none-macosx_11_0_arm64.whl (68.6 MB)\n",
      "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m68.6/68.6 MB\u001b[0m \u001b[31m1.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m00:01\u001b[0m00:02\u001b[0m\n",
      "\u001b[?25hRequirement already satisfied: setuptools>69 in /Users/taoxiaoyin/miniconda3/lib/python3.13/site-packages (from pymilvus==2.5.10->pymilvus[model]==2.5.10) (78.1.1)\n",
      "Collecting grpcio<=1.67.1,>=1.49.1 (from pymilvus==2.5.10->pymilvus[model]==2.5.10)\n",
      "  Downloading https://mirrors.aliyun.com/pypi/packages/d0/ae/ea2ff6bd2475a082eb97db1104a903cf5fc57c88c87c10b3c3f41a184fc0/grpcio-1.67.1-cp313-cp313-macosx_10_13_universal2.whl (10.9 MB)\n",
      "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m10.9/10.9 MB\u001b[0m \u001b[31m2.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0ma \u001b[36m0:00:01\u001b[0m\n",
      "\u001b[?25hCollecting protobuf>=3.20.0 (from pymilvus==2.5.10->pymilvus[model]==2.5.10)\n",
      "  Downloading https://mirrors.aliyun.com/pypi/packages/6a/c9/b9689a2a250264a84e66c46d8862ba788ee7a641cdca39bccf64f59284b7/protobuf-6.31.1-cp39-abi3-macosx_10_9_universal2.whl (425 kB)\n",
      "Collecting python-dotenv<2.0.0,>=1.0.1 (from pymilvus==2.5.10->pymilvus[model]==2.5.10)\n",
      "  Downloading https://mirrors.aliyun.com/pypi/packages/5f/ed/539768cf28c661b5b068d66d96a2f155c4971a5d55684a514c1a0e0dec2f/python_dotenv-1.1.1-py3-none-any.whl (20 kB)\n",
      "Collecting ujson>=2.0.0 (from pymilvus==2.5.10->pymilvus[model]==2.5.10)\n",
      "  Downloading https://mirrors.aliyun.com/pypi/packages/32/8a/9b748eb543c6cabc54ebeaa1f28035b1bd09c0800235b08e85990734c41e/ujson-5.10.0-cp313-cp313-macosx_11_0_arm64.whl (51 kB)\n",
      "Collecting pandas>=1.2.4 (from pymilvus==2.5.10->pymilvus[model]==2.5.10)\n",
      "  Downloading https://mirrors.aliyun.com/pypi/packages/c7/db/d8f24a7cc9fb0972adab0cc80b6817e8bef888cfd0024eeb5a21c0bb5c4a/pandas-2.3.1-cp313-cp313-macosx_11_0_arm64.whl (10.7 MB)\n",
      "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m10.7/10.7 MB\u001b[0m \u001b[31m2.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m00:01\u001b[0m00:01\u001b[0m\n",
      "\u001b[?25hCollecting milvus-lite>=2.4.0 (from pymilvus==2.5.10->pymilvus[model]==2.5.10)\n",
      "  Downloading https://mirrors.aliyun.com/pypi/packages/9b/2e/746f5bb1d6facd1e73eb4af6dd5efda11125b0f29d7908a097485ca6cad9/milvus_lite-2.5.1-py3-none-macosx_11_0_arm64.whl (24.4 MB)\n",
      "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m24.4/24.4 MB\u001b[0m \u001b[31m2.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m00:01\u001b[0m00:01\u001b[0m\n",
      "\u001b[?25hRequirement already satisfied: anyio<5,>=3.5.0 in /Users/taoxiaoyin/miniconda3/lib/python3.13/site-packages (from openai==1.82.0) (4.9.0)\n",
      "Requirement already satisfied: distro<2,>=1.7.0 in /Users/taoxiaoyin/miniconda3/lib/python3.13/site-packages (from openai==1.82.0) (1.9.0)\n",
      "Requirement already satisfied: httpx<1,>=0.23.0 in /Users/taoxiaoyin/miniconda3/lib/python3.13/site-packages (from openai==1.82.0) (0.28.1)\n",
      "Collecting jiter<1,>=0.4.0 (from openai==1.82.0)\n",
      "  Downloading https://mirrors.aliyun.com/pypi/packages/91/e3/0916334936f356d605f54cc164af4060e3e7094364add445a3bc79335d46/jiter-0.10.0-cp313-cp313-macosx_11_0_arm64.whl (318 kB)\n",
      "Requirement already satisfied: pydantic<3,>=1.9.0 in /Users/taoxiaoyin/miniconda3/lib/python3.13/site-packages (from openai==1.82.0) (2.11.7)\n",
      "Requirement already satisfied: sniffio in /Users/taoxiaoyin/miniconda3/lib/python3.13/site-packages (from openai==1.82.0) (1.3.1)\n",
      "Requirement already satisfied: typing-extensions<5,>=4.11 in /Users/taoxiaoyin/miniconda3/lib/python3.13/site-packages (from openai==1.82.0) (4.12.2)\n",
      "Requirement already satisfied: charset-normalizer<4,>=2 in /Users/taoxiaoyin/miniconda3/lib/python3.13/site-packages (from requests==2.32.3) (3.3.2)\n",
      "Requirement already satisfied: idna<4,>=2.5 in /Users/taoxiaoyin/miniconda3/lib/python3.13/site-packages (from requests==2.32.3) (3.7)\n",
      "Requirement already satisfied: urllib3<3,>=1.21.1 in /Users/taoxiaoyin/miniconda3/lib/python3.13/site-packages (from requests==2.32.3) (2.5.0)\n",
      "Requirement already satisfied: certifi>=2017.4.17 in /Users/taoxiaoyin/miniconda3/lib/python3.13/site-packages (from requests==2.32.3) (2025.7.14)\n",
      "Collecting filelock (from torch==2.7.0)\n",
      "  Downloading https://mirrors.aliyun.com/pypi/packages/4d/36/2a115987e2d8c300a974597416d9de88f2444426de9571f4b59b2cca3acc/filelock-3.18.0-py3-none-any.whl (16 kB)\n",
      "Collecting sympy>=1.13.3 (from torch==2.7.0)\n",
      "  Downloading https://mirrors.aliyun.com/pypi/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl (6.3 MB)\n",
      "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m6.3/6.3 MB\u001b[0m \u001b[31m1.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0ma \u001b[36m0:00:01\u001b[0m\n",
      "\u001b[?25hCollecting networkx (from torch==2.7.0)\n",
      "  Downloading https://mirrors.aliyun.com/pypi/packages/eb/8d/776adee7bbf76365fdd7f2552710282c79a4ead5d2a46408c9043a2b70ba/networkx-3.5-py3-none-any.whl (2.0 MB)\n",
      "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m2.0/2.0 MB\u001b[0m \u001b[31m1.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0ma \u001b[36m0:00:01\u001b[0m\n",
      "\u001b[?25hRequirement already satisfied: jinja2 in /Users/taoxiaoyin/miniconda3/lib/python3.13/site-packages (from torch==2.7.0) (3.1.6)\n",
      "Collecting fsspec (from torch==2.7.0)\n",
      "  Downloading https://mirrors.aliyun.com/pypi/packages/2f/e0/014d5d9d7a4564cf1c40b5039bc882db69fd881111e03ab3657ac0b218e2/fsspec-2025.7.0-py3-none-any.whl (199 kB)\n",
      "Collecting pymilvus.model>=0.3.0 (from pymilvus[model]==2.5.10)\n",
      "  Downloading https://mirrors.aliyun.com/pypi/packages/5b/ba/b34e3f8c57c453c02daf1a1eff9c4b62a2e89fc10a29bc83fb685155fe14/pymilvus_model-0.3.2-py3-none-any.whl (47 kB)\n",
      "Requirement already satisfied: httpcore==1.* in /Users/taoxiaoyin/miniconda3/lib/python3.13/site-packages (from httpx<1,>=0.23.0->openai==1.82.0) (1.0.9)\n",
      "Requirement already satisfied: h11>=0.16 in /Users/taoxiaoyin/miniconda3/lib/python3.13/site-packages (from httpcore==1.*->httpx<1,>=0.23.0->openai==1.82.0) (0.16.0)\n",
      "Requirement already satisfied: annotated-types>=0.6.0 in /Users/taoxiaoyin/miniconda3/lib/python3.13/site-packages (from pydantic<3,>=1.9.0->openai==1.82.0) (0.6.0)\n",
      "Requirement already satisfied: pydantic-core==2.33.2 in /Users/taoxiaoyin/miniconda3/lib/python3.13/site-packages (from pydantic<3,>=1.9.0->openai==1.82.0) (2.33.2)\n",
      "Requirement already satisfied: typing-inspection>=0.4.0 in /Users/taoxiaoyin/miniconda3/lib/python3.13/site-packages (from pydantic<3,>=1.9.0->openai==1.82.0) (0.4.0)\n",
      "Collecting numpy>=1.26.0 (from pandas>=1.2.4->pymilvus==2.5.10->pymilvus[model]==2.5.10)\n",
      "  Downloading https://mirrors.aliyun.com/pypi/packages/78/45/d4698c182895af189c463fc91d70805d455a227261d950e4e0f1310c2550/numpy-2.3.2-cp313-cp313-macosx_14_0_arm64.whl (5.1 MB)\n",
      "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m5.1/5.1 MB\u001b[0m \u001b[31m2.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m00:01\u001b[0m00:01\u001b[0m\n",
      "\u001b[?25hRequirement already satisfied: python-dateutil>=2.8.2 in /Users/taoxiaoyin/miniconda3/lib/python3.13/site-packages (from pandas>=1.2.4->pymilvus==2.5.10->pymilvus[model]==2.5.10) (2.9.0.post0)\n",
      "Collecting pytz>=2020.1 (from pandas>=1.2.4->pymilvus==2.5.10->pymilvus[model]==2.5.10)\n",
      "  Downloading https://mirrors.aliyun.com/pypi/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl (509 kB)\n",
      "Collecting tzdata>=2022.7 (from pandas>=1.2.4->pymilvus==2.5.10->pymilvus[model]==2.5.10)\n",
      "  Downloading https://mirrors.aliyun.com/pypi/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl (347 kB)\n",
      "Collecting transformers>=4.36.0 (from pymilvus.model>=0.3.0->pymilvus[model]==2.5.10)\n",
      "  Downloading https://mirrors.aliyun.com/pypi/packages/cc/34/4d82dc596764de9d14285f8ed53b50896bf05fbbcd71a82c6d174b3ab8c7/transformers-4.54.0-py3-none-any.whl (11.2 MB)\n",
      "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m11.2/11.2 MB\u001b[0m \u001b[31m2.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0ma \u001b[36m0:00:01\u001b[0m\n",
      "\u001b[?25hCollecting onnxruntime (from pymilvus.model>=0.3.0->pymilvus[model]==2.5.10)\n",
      "  Downloading https://mirrors.aliyun.com/pypi/packages/e0/39/77cefa829740bd830915095d8408dce6d731b244e24b1f64fe3df9f18e86/onnxruntime-1.22.1-cp313-cp313-macosx_13_0_universal2.whl (34.3 MB)\n",
      "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m34.3/34.3 MB\u001b[0m \u001b[31m1.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m00:01\u001b[0m00:01\u001b[0m\n",
      "\u001b[?25hCollecting scipy>=1.10.0 (from pymilvus.model>=0.3.0->pymilvus[model]==2.5.10)\n",
      "  Downloading https://mirrors.aliyun.com/pypi/packages/58/46/63477fc1246063855969cbefdcee8c648ba4b17f67370bd542ba56368d0b/scipy-1.16.0-cp313-cp313-macosx_14_0_arm64.whl (20.7 MB)\n",
      "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m20.7/20.7 MB\u001b[0m \u001b[31m2.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m00:01\u001b[0m00:01\u001b[0m\n",
      "\u001b[?25hRequirement already satisfied: six>=1.5 in /Users/taoxiaoyin/miniconda3/lib/python3.13/site-packages (from python-dateutil>=2.8.2->pandas>=1.2.4->pymilvus==2.5.10->pymilvus[model]==2.5.10) (1.17.0)\n",
      "Collecting mpmath<1.4,>=1.1.0 (from sympy>=1.13.3->torch==2.7.0)\n",
      "  Downloading https://mirrors.aliyun.com/pypi/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl (536 kB)\n",
      "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m536.2/536.2 kB\u001b[0m \u001b[31m1.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0mm-:--:--\u001b[0m\n",
      "\u001b[?25hCollecting huggingface-hub<1.0,>=0.34.0 (from transformers>=4.36.0->pymilvus.model>=0.3.0->pymilvus[model]==2.5.10)\n",
      "  Downloading https://mirrors.aliyun.com/pypi/packages/8c/cf/dd53c0132f50f258b06dd37a4616817b1f1f6a6b38382c06effd04bb6881/huggingface_hub-0.34.1-py3-none-any.whl (558 kB)\n",
      "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m558.8/558.8 kB\u001b[0m \u001b[31m2.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0mm-:--:--\u001b[0m\n",
      "\u001b[?25hRequirement already satisfied: packaging>=20.0 in /Users/taoxiaoyin/miniconda3/lib/python3.13/site-packages (from transformers>=4.36.0->pymilvus.model>=0.3.0->pymilvus[model]==2.5.10) (24.2)\n",
      "Requirement already satisfied: pyyaml>=5.1 in /Users/taoxiaoyin/miniconda3/lib/python3.13/site-packages (from transformers>=4.36.0->pymilvus.model>=0.3.0->pymilvus[model]==2.5.10) (6.0.2)\n",
      "Collecting regex!=2019.12.17 (from transformers>=4.36.0->pymilvus.model>=0.3.0->pymilvus[model]==2.5.10)\n",
      "  Downloading https://mirrors.aliyun.com/pypi/packages/09/c9/4e68181a4a652fb3ef5099e077faf4fd2a694ea6e0f806a7737aff9e758a/regex-2024.11.6-cp313-cp313-macosx_11_0_arm64.whl (284 kB)\n",
      "Collecting tokenizers<0.22,>=0.21 (from transformers>=4.36.0->pymilvus.model>=0.3.0->pymilvus[model]==2.5.10)\n",
      "  Downloading https://mirrors.aliyun.com/pypi/packages/6c/e6/33f41f2cc7861faeba8988e7a77601407bf1d9d28fc79c5903f8f77df587/tokenizers-0.21.2-cp39-abi3-macosx_11_0_arm64.whl (2.7 MB)\n",
      "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m2.7/2.7 MB\u001b[0m \u001b[31m2.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0ma \u001b[36m0:00:01\u001b[0m\n",
      "\u001b[?25hCollecting safetensors>=0.4.3 (from transformers>=4.36.0->pymilvus.model>=0.3.0->pymilvus[model]==2.5.10)\n",
      "  Downloading https://mirrors.aliyun.com/pypi/packages/b8/3b/11f1b4a2f5d2ab7da34ecc062b0bc301f2be024d110a6466726bec8c055c/safetensors-0.5.3-cp38-abi3-macosx_11_0_arm64.whl (418 kB)\n",
      "Collecting hf-xet<2.0.0,>=1.1.3 (from huggingface-hub<1.0,>=0.34.0->transformers>=4.36.0->pymilvus.model>=0.3.0->pymilvus[model]==2.5.10)\n",
      "  Downloading https://mirrors.aliyun.com/pypi/packages/de/5f/2c78e28f309396e71ec8e4e9304a6483dcbc36172b5cea8f291994163425/hf_xet-1.1.5-cp37-abi3-macosx_11_0_arm64.whl (2.6 MB)\n",
      "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m2.6/2.6 MB\u001b[0m \u001b[31m2.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0ma \u001b[36m0:00:01\u001b[0m\n",
      "\u001b[?25hRequirement already satisfied: MarkupSafe>=2.0 in /Users/taoxiaoyin/miniconda3/lib/python3.13/site-packages (from jinja2->torch==2.7.0) (3.0.2)\n",
      "Collecting coloredlogs (from onnxruntime->pymilvus.model>=0.3.0->pymilvus[model]==2.5.10)\n",
      "  Downloading https://mirrors.aliyun.com/pypi/packages/a7/06/3d6badcf13db419e25b07041d9c7b4a2c331d3f4e7134445ec5df57714cd/coloredlogs-15.0.1-py2.py3-none-any.whl (46 kB)\n",
      "Collecting flatbuffers (from onnxruntime->pymilvus.model>=0.3.0->pymilvus[model]==2.5.10)\n",
      "  Downloading https://mirrors.aliyun.com/pypi/packages/b8/25/155f9f080d5e4bc0082edfda032ea2bc2b8fab3f4d25d46c1e9dd22a1a89/flatbuffers-25.2.10-py2.py3-none-any.whl (30 kB)\n",
      "Collecting humanfriendly>=9.1 (from coloredlogs->onnxruntime->pymilvus.model>=0.3.0->pymilvus[model]==2.5.10)\n",
      "  Downloading https://mirrors.aliyun.com/pypi/packages/f0/0f/310fb31e39e2d734ccaa2c0fb981ee41f7bd5056ce9bc29b2248bd569169/humanfriendly-10.0-py2.py3-none-any.whl (86 kB)\n",
      "Installing collected packages: pytz, mpmath, flatbuffers, ujson, tzdata, sympy, safetensors, requests, regex, python-dotenv, protobuf, numpy, networkx, milvus-lite, jiter, humanfriendly, hf-xet, grpcio, fsspec, filelock, torch, scipy, pandas, huggingface-hub, coloredlogs, tokenizers, pymilvus, openai, onnxruntime, transformers, pymilvus.model\n",
      "\u001b[2K  Attempting uninstall: requestsm━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m 5/31\u001b[0m [sympy]]\n",
      "\u001b[2K    Found existing installation: requests 2.32.4━━━━━━━━━━━━━━\u001b[0m \u001b[32m 5/31\u001b[0m [sympy]\n",
      "\u001b[2K    Uninstalling requests-2.32.4:━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m 5/31\u001b[0m [sympy]\n",
      "\u001b[2K      Successfully uninstalled requests-2.32.4━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m 5/31\u001b[0m [sympy]\n",
      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m31/31\u001b[0m [pymilvus.model]m [transformers]ub]\n",
      "\u001b[1A\u001b[2KSuccessfully installed coloredlogs-15.0.1 filelock-3.18.0 flatbuffers-25.2.10 fsspec-2025.7.0 grpcio-1.67.1 hf-xet-1.1.5 huggingface-hub-0.34.1 humanfriendly-10.0 jiter-0.10.0 milvus-lite-2.5.1 mpmath-1.3.0 networkx-3.5 numpy-2.3.2 onnxruntime-1.22.1 openai-1.82.0 pandas-2.3.1 protobuf-6.31.1 pymilvus-2.5.10 pymilvus.model-0.3.2 python-dotenv-1.1.1 pytz-2025.2 regex-2024.11.6 requests-2.32.3 safetensors-0.5.3 scipy-1.16.0 sympy-1.14.0 tokenizers-0.21.2 torch-2.7.0 transformers-4.54.0 tzdata-2025.2 ujson-5.10.0\n"
     ]
    }
   ],
   "source": [
    "!pip install \"pymilvus[model]==2.5.10\" openai==1.82.0 requests==2.32.3 tqdm==4.67.1 torch==2.7.0"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1b3c0999-d670-41a9-afbd-d8a020fe1631",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    "---"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "375ad823",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "\n",
    "# 从环境变量获取 DeepSeek API Key\n",
    "api_key = os.getenv(\"DEEPSEEK_API_KEY\")\n",
    "os.environ[\"TOKENIZERS_PARALLELISM\"] = \"false\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "db44bb26",
   "metadata": {},
   "source": [
    "### 准备数据"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "25f92a95",
   "metadata": {},
   "source": [
    "我们使用 Milvus 文档 2.4.x 中的 FAQ 页面作为我们 RAG 中的私有知识库，这是一个简单 RAG 管道的良好数据源。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a1a8b9e2",
   "metadata": {},
   "source": [
    "下载 zip 文件并将文档解压到 `milvus_docs` 文件夹。\n",
    "\n",
    "**建议在命令行执行下面命令**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "a81fa031",
   "metadata": {},
   "outputs": [],
   "source": [
    "#!wget https://github.com/milvus-io/milvus-docs/releases/download/v2.4.6-preview/milvus_docs_2.4.x_en.zip\n",
    "#!unzip -q milvus_docs_2.4.x_en.zip -d milvus_docs"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d1198466",
   "metadata": {},
   "source": [
    "我们从 `milvus_docs/en/faq` 文件夹加载所有 markdown 文件。对于每个文档，我们简单地使用 \"# \" 来分割文件中的内容，这样可以大致分离出 markdown 文件中每个主要部分的内容。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "c9035a5f",
   "metadata": {},
   "outputs": [],
   "source": [
    "from glob import glob\n",
    "\n",
    "text_lines = []\n",
    "\n",
    "for file_path in glob(\"milvus_docs/en/faq/*.md\", recursive=True):\n",
    "    with open(file_path, \"r\") as file:\n",
    "        file_text = file.read()\n",
    "\n",
    "    text_lines += file_text.split(\"# \")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "01b73e74-ee7d-4daf-b7db-1c7a10bfc0bf",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(text_lines)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4cc2a0b8",
   "metadata": {},
   "source": [
    "### 准备 LLM 和 Embedding 模型"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "19eaff7a",
   "metadata": {},
   "source": [
    "DeepSeek 支持 OpenAI 风格的 API，您可以使用相同的 API 进行微小调整来调用 LLM。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "b994eb47",
   "metadata": {},
   "outputs": [],
   "source": [
    "from openai import OpenAI\n",
    "\n",
    "deepseek_client = OpenAI(\n",
    "    api_key=api_key,\n",
    "    base_url=\"https://api.deepseek.com/v1\",  # DeepSeek API 的基地址\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1cc5a5e2",
   "metadata": {},
   "source": [
    "定义一个 embedding 模型，使用 `milvus_model` 来生成文本嵌入。我们以 `DefaultEmbeddingFunction` 模型为例，这是一个预训练的轻量级嵌入模型。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "3a94242a",
   "metadata": {},
   "outputs": [],
   "source": [
    "from pymilvus import model as milvus_model\n",
    "\n",
    "embedding_model = milvus_model.DefaultEmbeddingFunction()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "93fb1696",
   "metadata": {},
   "source": [
    "生成一个测试嵌入并打印其维度和前几个元素。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "88a27567",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "768\n",
      "[-0.04836056  0.07163018 -0.01130064 -0.03789344 -0.03320646 -0.01318444\n",
      " -0.03041711 -0.02269505 -0.02317867 -0.00426023]\n"
     ]
    }
   ],
   "source": [
    "test_embedding = embedding_model.encode_queries([\"This is a test\"])[0]\n",
    "embedding_dim = len(test_embedding)\n",
    "print(embedding_dim)\n",
    "print(test_embedding[:10])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "f7683f3a-d9e4-4c8e-9a66-c341911bef6b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[-0.0275297   0.06088526  0.00388529 -0.00215193 -0.02774976 -0.01186187\n",
      " -0.04020914 -0.06023425 -0.03813157  0.01002724]\n"
     ]
    }
   ],
   "source": [
    "test_embedding_0 = embedding_model.encode_queries([\"That is a test\"])[0]\n",
    "print(test_embedding_0[:10])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5a778887",
   "metadata": {},
   "source": [
    "## 将数据加载到 Milvus"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "02b23a24",
   "metadata": {},
   "source": [
    "### 创建 Collection"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "95e84b8c",
   "metadata": {},
   "outputs": [],
   "source": [
    "from pymilvus import MilvusClient\n",
    "\n",
    "milvus_client = MilvusClient(uri=\"./milvus_demo.db\")\n",
    "\n",
    "collection_name = \"my_rag_collection\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "68648561",
   "metadata": {},
   "source": [
    "关于 `MilvusClient` 的参数：\n",
    "\n",
    "*   将 `uri` 设置为本地文件，例如 `./milvus.db`，是最方便的方法，因为它会自动利用 Milvus Lite 将所有数据存储在此文件中。\n",
    "*   如果您有大规模数据，可以在 Docker 或 Kubernetes 上设置性能更高的 Milvus 服务器。在此设置中，请使用服务器 URI，例如 `http://localhost:19530`，作为您的 `uri`。\n",
    "*   如果您想使用 Zilliz Cloud（Milvus 的完全托管云服务），请调整 `uri` 和 `token`，它们对应 Zilliz Cloud 中的 Public Endpoint 和 Api key。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5ce1bf3e",
   "metadata": {},
   "source": [
    "检查 collection 是否已存在，如果存在则删除它。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "aee85c08",
   "metadata": {},
   "outputs": [],
   "source": [
    "if milvus_client.has_collection(collection_name):\n",
    "    milvus_client.drop_collection(collection_name)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "73eb379f",
   "metadata": {},
   "source": [
    "创建一个具有指定参数的新 collection。\n",
    "\n",
    "如果我们不指定任何字段信息，Milvus 将自动创建一个默认的 `id` 字段作为主键，以及一个 `vector` 字段来存储向量数据。一个保留的 JSON 字段用于存储非 schema 定义的字段及其值。\n",
    "\n",
    "`metric_type` (距离度量类型):\n",
    "     作用：定义如何计算向量之间的相似程度。\n",
    "     例如：`IP` (内积) - 值越大通常越相似；`L2` (欧氏距离) - 值越小越相似；`COSINE` (余弦相似度) - 通常转换为距离，值越小越相似。\n",
    "     选择依据：根据你的嵌入模型的特性和期望的相似性定义来选择。\n",
    "\n",
    " `consistency_level` (一致性级别):\n",
    "     作用：定义数据写入后，读取操作能多快看到这些新数据。\n",
    "     例如：\n",
    "         `Strong` (强一致性): 总是读到最新数据，可能稍慢。\n",
    "         `Bounded` (有界过期): 可能读到几秒内旧数据，性能较好 (默认)。\n",
    "         `Session` (会话一致性): 自己写入的自己能立刻读到。\n",
    "         `Eventually` (最终一致性): 最终会读到新数据，但没时间保证，性能最好。\n",
    "     选择依据：在数据实时性要求和系统性能之间做权衡。\n",
    "\n",
    "简单来说：\n",
    " `metric_type`：怎么算相似。\n",
    " `consistency_level`：新数据多久能被读到。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "bd0b2df8",
   "metadata": {},
   "outputs": [],
   "source": [
    "milvus_client.create_collection(\n",
    "    collection_name=collection_name,\n",
    "    dimension=embedding_dim,\n",
    "    metric_type=\"IP\",  # 内积距离\n",
    "    consistency_level=\"Strong\",  # 支持的值为 (`\"Strong\"`, `\"Session\"`, `\"Bounded\"`, `\"Eventually\"`)。更多详情请参见 https://milvus.io/docs/consistency.md#Consistency-Level。\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9c15bafb",
   "metadata": {},
   "source": [
    "### 插入数据"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "171d3b35",
   "metadata": {},
   "source": [
    "遍历文本行，创建嵌入，然后将数据插入 Milvus。\n",
    "\n",
    "这里有一个新字段 `text`，它是在 collection schema 中未定义的字段。它将自动添加到保留的 JSON 动态字段中，该字段在高级别上可以被视为普通字段。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "ad077094",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Creating embeddings: 0it [00:00, ?it/s]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'insert_count': 0, 'ids': []}"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from tqdm import tqdm\n",
    "\n",
    "data = []\n",
    "\n",
    "doc_embeddings = embedding_model.encode_documents(text_lines)\n",
    "\n",
    "for i, line in enumerate(tqdm(text_lines, desc=\"Creating embeddings\")):\n",
    "    data.append({\"id\": i, \"vector\": doc_embeddings[i], \"text\": line})\n",
    "\n",
    "milvus_client.insert(collection_name=collection_name, data=data)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd971f6b",
   "metadata": {},
   "source": [
    "## 构建 RAG"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "534dc076",
   "metadata": {},
   "source": [
    "### 检索查询数据"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5a6fd7e7",
   "metadata": {},
   "source": [
    "我们指定一个关于 Milvus 的常见问题。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "6e2f5c6a",
   "metadata": {},
   "outputs": [],
   "source": [
    "question = \"How is data stored in milvus?\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "52401a38",
   "metadata": {},
   "source": [
    "在 collection 中搜索该问题，并检索语义上最匹配的前3个结果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "0dd4cbac",
   "metadata": {},
   "outputs": [],
   "source": [
    "search_res = milvus_client.search(\n",
    "    collection_name=collection_name,\n",
    "    data=embedding_model.encode_queries(\n",
    "        [question]\n",
    "    ),  # 将问题转换为嵌入向量\n",
    "    limit=3,  # 返回前3个结果\n",
    "    search_params={\"metric_type\": \"IP\", \"params\": {}},  # 内积距离\n",
    "    output_fields=[\"text\"],  # 返回 text 字段\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ffcce135",
   "metadata": {},
   "source": [
    "让我们看一下查询的搜索结果"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "6a7f6eb3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[]\n"
     ]
    }
   ],
   "source": [
    "import json\n",
    "\n",
    "retrieved_lines_with_distances = [\n",
    "    (res[\"entity\"][\"text\"], res[\"distance\"]) for res in search_res[0]\n",
    "]\n",
    "print(json.dumps(retrieved_lines_with_distances, indent=4))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ccd4c186",
   "metadata": {},
   "source": [
    "### 使用 LLM 获取 RAG 响应"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4cd1ae3a",
   "metadata": {},
   "source": [
    "将检索到的文档转换为字符串格式。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "0676448f",
   "metadata": {},
   "outputs": [],
   "source": [
    "context = \"\\n\".join(\n",
    "    [line_with_distance[0] for line_with_distance in retrieved_lines_with_distances]\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "107df42a-b3f7-48a8-b66b-fc82fe3ec174",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "''"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "context"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "19998758-7f98-4cb8-8789-625fcfaad00e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'How is data stored in milvus?'"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "question"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7ad25756",
   "metadata": {},
   "source": [
    "为语言模型定义系统和用户提示。此提示是使用从 Milvus 检索到的文档组装而成的。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "b655f6f3",
   "metadata": {},
   "outputs": [],
   "source": [
    "SYSTEM_PROMPT = \"\"\"\n",
    "Human: 你是一个 AI 助手。你能够从提供的上下文段落片段中找到问题的答案。\n",
    "\"\"\"\n",
    "USER_PROMPT = f\"\"\"\n",
    "请使用以下用 <context> 标签括起来的信息片段来回答用 <question> 标签括起来的问题。最后追加原始回答的中文翻译，并用 <translated>和</translated> 标签标注。\n",
    "<context>\n",
    "{context}\n",
    "</context>\n",
    "<question>\n",
    "{question}\n",
    "</question>\n",
    "<translated>\n",
    "</translated>\n",
    "\"\"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "97089c31-f85c-47a9-8498-78520513bc67",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'\\n请使用以下用 <context> 标签括起来的信息片段来回答用 <question> 标签括起来的问题。最后追加原始回答的中文翻译，并用 <translated>和</translated> 标签标注。\\n<context>\\n\\n</context>\\n<question>\\nHow is data stored in milvus?\\n</question>\\n<translated>\\n</translated>\\n'"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "USER_PROMPT"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "184b457f",
   "metadata": {},
   "source": [
    "使用 DeepSeek 提供的 `deepseek-chat` 模型根据提示生成响应。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "638a7561",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "由于提供的上下文片段为空，我无法基于具体信息回答Milvus的数据存储机制。不过根据公开知识，我可以提供一般性说明：\n",
      "\n",
      "Milvus作为向量数据库，其数据存储主要特点包括：\n",
      "1. 向量数据通过近似最近邻(ANN)算法索引存储在磁盘\n",
      "2. 支持多种索引类型（IVF_FLAT、HNSW等）\n",
      "3. 元数据通常存储在MySQL/PostgreSQL等关系型数据库\n",
      "4. 采用日志结构化合并树(LSM)架构处理写入\n",
      "\n",
      "建议补充具体上下文以获得更精确的答案。\n",
      "\n",
      "<translated>\n",
      "由于提供的上下文内容为空，我无法根据具体信息回答Milvus的数据存储方式。但根据公开资料，其典型存储特征包括：\n",
      "1. 向量数据经ANN算法索引后持久化存储\n",
      "2. 兼容IVF_FLAT/HNSW等多种索引格式  \n",
      "3. 元数据依赖MySQL/PostgreSQL等关系数据库\n",
      "4. 基于LSM树结构优化写入性能\n",
      "\n",
      "如需准确回答请提供相关技术文档片段。\n",
      "</translated>\n"
     ]
    }
   ],
   "source": [
    "response = deepseek_client.chat.completions.create(\n",
    "    model=\"deepseek-chat\",\n",
    "    messages=[\n",
    "        {\"role\": \"system\", \"content\": SYSTEM_PROMPT},\n",
    "        {\"role\": \"user\", \"content\": USER_PROMPT},\n",
    "    ],\n",
    ")\n",
    "print(response.choices[0].message.content)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "50ce3b55-7daa-4727-95bd-3b00f6aa2b03",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "545d33c6-1826-4c27-919b-18777d3f41d2",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
